home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
infoplus.zip
/
INFOPLUS.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-06-25
|
16KB
|
565 lines
page 75, 110
;--------------------------------------------------------------------
;
; INFOPLUS.ASM
;
; Version 1.0
;
; Two subprograms used by INFOPLUS.PAS:
;
; CPUID - identifies host CPU and NDP (if
; any)
; DISKREAD - reads absolute sectors from disk
;
; Originally by:
; Steve Grant
; Long Beach, CA
; January 13, 1989
;
; mods by Andrew Rossmann (6/24/90)
; 286/386/486 detection adapted from code by Robert Collins.
;--------------------------------------------------------------------
.286P
.8087
public CPUID, DISKREAD
;-----------------------------------------------------------------------------
; 80486 instruction macro -- because MASM 5.1 doesn't support the 80486!
;-----------------------------------------------------------------------------
XADD macro
db 0fh,0C0h,0D2h ; 80486 instruction macro
ENDM
CODE segment byte
; Conditional jumps are all coded with the SHORT qualifier in
; order to minimize the size of the .OBJ file output of Turbo
; Assembler.
;--------------------------------------------------------------------
CPUID proc near
assume cs:CODE, ds:DATA, es:nothing, ss:nothing
; On entry:
;
; BP
; SP => near return address
; offset of a cpu_info_t record
; segment " " " "
;
; On exit, the cpu_info_t record has been filled in as follows:
;
; byte = CPU type
; word = Machine Status Word
; 6 bytes = Global Descriptor Table
; 6 bytes = Interrupt Descriptor Table
; boolean = segment register change/interrupt flag
; byte = NDP type
; word = NDP control word
mCPU equ byte ptr [bx]
mMSW equ word ptr [bx + 1]
mGDT equ [bx + 3]
mIDT equ [bx + 9]
mchkint equ byte ptr [bx + 15]
mNDP equ byte ptr [bx + 16]
mNDPCW equ word ptr [bx + 17]
f8088 equ 0
f8086 equ 1
fV20 equ 2
fV30 equ 3
f80188 equ 4
f80186 equ 5
f80286 equ 6
f80386 equ 7
f80486 equ 8
funk = 0FFH
false equ 0
true equ 1
push bp
mov bp,sp
push ds
lds bx,[bp + 4]
call cpu
call chkint
call ndp
pop ds
pop bp
ret 4
;--------------------------------------------------------------------
cpu:
; interrupt of multi-prefix string instruction
mov mCPU,funk ;set CPU type to unknown
sti
mov cx,0FFFFH
rep lods byte ptr es:[si]
jcxz short cpu_02
call piq
cmp dx,4
jg short cpu_01
mov mCPU,f8088
ret
cpu_01:
cmp dx,6
jne short cpu_01a
mov mCPU,f8086
cpu_01a:
ret
cpu_02:
; number of bits in displacement register used by shift
mov al,0FFH
mov cl,20H
shl al,cl
or al,al
jnz short cpu_04
call piq
cmp dx,4
jg short cpu_03
mov mCPU,fV20
ret
cpu_03:
cmp dx,6
jne short CPUID_done
mov mCPU,fV30
ret
cpu_04:
; order of write/decrement by PUSH SP
push sp
pop ax
cmp ax,sp
je short cpu_06
call piq
cmp dx,4
jg short cpu_05
mov mCPU,f80188
ret
cpu_05:
cmp dx,6
jne short CPUID_done
mov mCPU,f80186
ret
; The following code is adapted from a program by Robert Collins
;since we probably have a 286, 386 or 486, we'll trap the invalid opcode
;handler, and try to determine the cpu type by using various opcodes.
;First, though, grab some tables
cpu_06:
smsw mMSW
sgdt mGDT
sidt mIDT
;-----------------------------------------------------------------------------
; Setup INT6 handler
;-----------------------------------------------------------------------------
push bx ;save bx
mov ax,3506h ;get INT 6 pointer
int 21h
mov old_int06_seg,es ;save
mov old_int06_ofs,bx
push ds ;save DS
mov dx,seg INT6_handler ;point to new handler
mov ds,dx
mov dx,offset INT6_handler
mov ax,2506h ;put into effect
int 21h
pop ds ;restore DS
pop bx
mov mCPU,f80486 ; initialize CPU flag
xor cx,cx ; initialize semaphore
;-----------------------------------------------------------------------------
; Now, try and determine which CPU we are by executing invalid opcodes.
; The instructions I chose to invoke invalid opcodes, are themselves rather
; benign. In each case, the chosen instruction modifies the DX register,
; and nothing else. No system parameters are changed, e.g. protected mode,
; or other CPU dependant features.
;-----------------------------------------------------------------------------
; The 80486 instruction 'XADD' xchanges the registers, then adds them.
; The exact syntax for a '486 compiler would be: XADD DX,DX.
;-----------------------------------------------------------------------------
XADD ;DX,DX ; 80486
jcxz CPU_exit
mov mCPU,f80386 ; set 80386 semaphore
xor cx,cx ; CX=0
;-----------------------------------------------------------------------------
; For a description on the effects of the following instructions, look in
; the Intel Programmers Reference Manual's for the 80186, 80286, or 80386.
;-----------------------------------------------------------------------------
.386
mov edx,edx ; 80386
.286P
jcxz CPU_exit
mov mCPU,f80286 ; set 80286 semaphore
xor cx,cx ; CX=0
smsw dx ; 80286
jcxz CPU_exit
mov mCPU,funk ; set unknown CPU
CPU_exit:
push ds ;save DS
lds dx,old_int06 ;get old pointer
mov ax,2506h ;restore it
int 21h
pop ds
;!!!!!!!
;!!! Original 286/386 detection code. Commented out but left in in
;!!! case of problems.
;!!!!!!!
; try to alter flag register bits 15-12
;
; pushf
; pop ax
; mov cx,ax
; xor cx,0F000H
; push cx
; popf
; pushf
; pop cx
; cmp ax,cx
; jne short cpu_07
; mov mCPU,f80286
; ret
;cpu_07:
; mov mCPU,f80386
; ret
;cpu_08:
; mov mCPU,funk
CPUID_done:
ret
;--------------------------------------------------------------------
piq:
; On exit:
;
; DX = length of prefetch instruction queue
;
; This subroutine uses self-modifying code, but can
; nevertheless be run repeatedly in the course of the calling
; program.
count = 7
opincdx equ 42H ; inc dx opcode
opnop equ 90H ; nop opcode
mov al,opincdx
mov cx,count
push cx
push cs
pop es
mov di,offset piq_01 - 1
push di
std
rep stosb
mov al,opnop
pop di
pop cx
xor dx,dx
cli
rep stosb
rept count
inc dx
endm
piq_01:
sti
ret
;--------------------------------------------------------------------
chkint:
; save old INT 01H vector
push bx
mov ax,3501H
int 21H
mov old_int01_ofs,bx
mov old_int01_seg,es
pop bx
; redirect INT 01H vector
push ds
mov ax,2501H
mov dx,seg new_int01
mov ds,dx
mov dx,offset new_int01
int 21H
pop ds
; set TF and change SS -- did we trap on following instruction?
pushf
pop ax
or ah,01H ; set TF
push ax
popf
push ss ; CPU may wait one
; instruction before
; recognizing single step
; interrupt
pop ss
chkint_01: ; shouldn't ever trap here
; restore old INT 01H vector
push ds
mov ax,2501H
lds dx,old_int01
int 21H
pop ds
ret
;--------------------------------------------------------------------
new_int01:
; INT 01H handler (single step)
;
; On entry:
;
; SP => IP
; CS
; flags
sti
pop ax ; IP
cmp ax,offset chkint_01
jb short new_int01_03
je short new_int01_01
mov mchkint,false
jmp short new_int01_02
new_int01_01:
mov mchkint,true
new_int01_02:
pop cx ; CS
pop dx ; flags
and dh,0FEH ; turn off TF
push dx ; flags
push cx ; CS
new_int01_03:
push ax ; IP
iret
;-----------------------------------------------------------------------------
; INT6 handler sets a semaphore (CX=FFFF) and adjusts the return address to
; point past the invalid opcode.
;-----------------------------------------------------------------------------
INT6_handler:
enter 0,0 ; create new stack frame
dec cx ; make CX=FFFF
add word ptr ss:[bp][2],3 ; point past invalid opcode
leave
iret
;--------------------------------------------------------------------
ndp:
fnone equ 0
f8087 equ 1
f80287 equ 2
f80387 equ 3
funk = 0FFH
mov word ptr ndp_cw,0000H
cli
; The next three 80x87 instructions cannot carry the WAIT prefix,
; because there may not be an 80x87 for which to wait. The WAIT is
; therefore emulated with a MOV CX,<value>! LOOP $ combination.
; CPU NDP
fnsave ndp_save ; 14 221
mov cx,(221-6-1)/17+1 ; 4
loop $ ; 17*CX-12
; 17*CX+6
fninit ; 8 8
mov cx,(8-0-1)/17+1 ; 4
loop $ ; 17*CX-12
; 17*CX
fnstcw ndp_cw ; 14 24
mov cx,(24-2-1)/17+1 ; 4
loop $ ; 17*CX-12
; 17*CX+2
sti
mov ax,ndp_cw
cmp ax,0000H
jne short ndp_01
mov mNDP,fnone
ret
ndp_01:
cmp ax,03FFH
jne short ndp_02
mov mNDP,f8087
jmp short ndp_04
ndp_02:
.287
cmp ax,037FH
jne short ndp_05
fld1
fldz
fdiv
fld1
fchs
fldz
fdiv
fcom
fstsw ndp_sw
mov ax,ndp_sw
and ah,41H ; C3, C0
cmp ah,40H ; ST(0) = ST(1)
jne short ndp_03
mov mNDP,f80287
jmp short ndp_04
ndp_03:
cmp ah,01H ; ST(0) < ST(1)
jne short ndp_05
mov mNDP,f80387
ndp_04:
.8087
frstor ndp_save
fstcw mNDPCW
ret
ndp_05:
mov mNDP,funk
ret
CPUID endp
;--------------------------------------------------------------------
DISKREAD proc near
assume cs:CODE, ds:DATA, es:nothing
; On entry:
;
; BP
; SP => near return address
; offset of disk buffer
; segment " " "
; number of sectors to read
; starting logical sector number
; drive number (0=A, 1=B, etc.)
;
; On exit:
;
; AX = function result
; 00 - function successful
; 01..FF - DOS INT 25H error result
drive equ [bp + 12]
starting_sector equ [bp + 10]
number_of_sectors equ [bp + 8]
buffer equ [bp + 4]
push bp
mov bp,sp
mov ax,3000h ;get DOS version
int 21h
cmp al,4 ;DOS 4?
jb read3 ;Read assuming DOS 3.x
mov al,drive
mov bx,starting_sector ;copy info into parameter block
mov extd_starting_sector_lo,bx
mov extd_starting_sector_hi,0 ;We're only using lower part
mov bx,number_of_sectors
mov extd_number_of_sectors,bx
les bx,buffer ;get seg:ofs of buffer in ES:BX
mov extd_bufofs,bx ;put into block
mov extd_bufseg,es
mov bx,offset dos4_block ;DS:BX points to block
mov cx,-1 ;-1 means extended read
push ds ;save DS (not really needed, but lets
;me share code with DOS 3 read.)
jmp short readit
read3: mov al,drive
mov dx,starting_sector
mov cx,number_of_sectors
push ds
lds bx,buffer ;get seg:ofs of buffer in DS:BX
readit: int 25H
inc sp ; fix broken stack
inc sp
pop ds
jc short diskread_01
xor ax,ax
diskread_01:
pop bp
ret 10
DISKREAD endp
CODE ends
;--------------------------------------------------------------------
DATA segment byte
; storage for CPUID
; redirected INT 01H vector
old_int01 label dword
old_int01_ofs dw ?
old_int01_seg dw ?
; redirected INT 6 vector
old_int06 label dword
old_int06_ofs dw ?
old_int06_seg dw ?
; storage for NDPID
; 80x87 control word after initialization, status word after divide by zero
ndp_cw dw ?
ndp_save db 94 dup (?)
ndp_sw dw ?
; storage for DISKREAD
; DOS 4.0 extended read parameter block
dos4_block label byte
extd_starting_sector_lo dw ?
extd_starting_sector_hi dw ?
extd_number_of_sectors dw ?
extd_bufofs dw ?
extd_bufseg dw ?
DATA ends
end